using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Oops.Xna.Framework.UI
{
	// TODO : Not finished!!!
	public class ScreenSpaceService : IScreenSpaceService, IDisposable 
	{
		private Game game;

		private float basisWidth = 800;
		private float basisHeight = 450;

		private float widthRatio;
		private float heightRatio;

		private Matrix scale;

		public ScreenSpaceService(Game game)
		{
			// The game parameter must be specified.
			if (game == null)
			{
				throw new ArgumentNullException("game");
			}

			// Hold onto parameters.
			this.game = game;

			// Subscribe to some of the graphics device's events.
			game.GraphicsDevice.DeviceReset += new EventHandler(this.OnDeviceReset);

			// Initialize the ratios.
			this.CalculateRatios();

			// Add the service to the service container.
			game.AddService<IScreenSpaceService>(this, true);
		}

		~ScreenSpaceService()
		{
			// Dispose of unmanaged resources.
			this.Dispose(false);
		}

		#region IDisposable Members

		public void Dispose()
		{
			// Dispose of all resources and notify garbage collector that this instance
			// does not need to be finalized.
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		#endregion

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				lock (this)
				{
					// Remove self from the service container.
					if (this.game.GetService<IScreenSpaceService>(false) == this)
					{
						this.game.RemoveService<IScreenSpaceService>(true);
					}
				}
			}
		}

		#region IScreenSpaceService Members

		public float BasisWidth
		{
			get { return this.basisWidth; }
			set
			{
				if (this.basisWidth != value)
				{
					this.basisWidth = value;
					this.CalculateRatios();
				}
			}
		}

		public float BasisHeight
		{
			get { return this.basisHeight; }
			set
			{
				if (this.basisHeight != value)
				{
					this.basisHeight = value;
					this.CalculateRatios();
				}
			}
		}

		public Matrix Scale
		{
			get { return this.scale; }
		}

		public void PointToScreen(ref Point point, out Point result)
		{
#if XBOX
			result = new Point();
#endif
			result.X = (int)(point.X * this.widthRatio);
			result.Y = (int)(point.Y * this.heightRatio);
		}

		public void ScreenToPoint(ref Point point, out Point result)
		{
			throw new Exception("The method or operation is not implemented.");
		}

		public void Vector2ToScreen(ref Vector2 vector, out Vector2 result)
		{
#if XBOX
			result = new Vector2();
#endif
			result.X = vector.X * this.widthRatio;
			result.Y = vector.Y * this.heightRatio;
		}

		public void ScreenToVector2(ref Vector2 point, out Vector2 result)
		{
			throw new Exception("The method or operation is not implemented.");
		}

		#endregion

		private void OnDeviceReset(object sender, EventArgs e)
		{
			// Re-calculate the width and height ratios when the graphics device resets.
			this.CalculateRatios();
		}

		private void CalculateRatios()
		{
			// Calculate the width and height ratios.
			this.widthRatio = this.game.GraphicsDevice.PresentationParameters.BackBufferWidth / this.basisWidth;
			this.heightRatio = this.game.GraphicsDevice.PresentationParameters.BackBufferHeight / this.basisHeight;
#if XBOX
			float border = (1.0f - 0.8f) * 0.5f;
			this.scale = 
				Matrix.CreateScale(0.8f, 0.8f, 1.0f) *
				Matrix.CreateScale(this.widthRatio, this.heightRatio, 1.0f) *
				Matrix.CreateTranslation(new Vector3(border * this.game.GraphicsDevice.PresentationParameters.BackBufferWidth, border * this.game.GraphicsDevice.PresentationParameters.BackBufferHeight, 0.0f));
#else
			this.scale = Matrix.CreateScale(this.widthRatio, this.heightRatio, 1.0f);
#endif
		}
	}
}
